package com.docmgmt.mvp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.docmgmt.mvp.dto.*;
import com.docmgmt.mvp.entity.FileEntity;
import com.docmgmt.mvp.entity.FileShareEntity;
import com.docmgmt.mvp.entity.UserEntity;
import com.docmgmt.mvp.exception.BusinessException;
import com.docmgmt.mvp.exception.ForbiddenException;
import com.docmgmt.mvp.mapper.FileMapper;
import com.docmgmt.mvp.mapper.FileShareMapper;
import com.docmgmt.mvp.mapper.UserMapper;
import com.docmgmt.mvp.service.FileShareService;
import com.docmgmt.mvp.service.PermissionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * <p>
 * 文件分享表 服务实现类（v3.0）
 * </p>
 *
 * @author Dora
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FileShareServiceImpl extends ServiceImpl<FileShareMapper, FileShareEntity> implements FileShareService {

    private final FileShareMapper fileShareMapper;
    private final FileMapper fileMapper;
    private final UserMapper userMapper;
    private final PermissionService permissionService;

    @Value("${app.base-url:http://localhost:8080}")
    private String baseUrl;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileShareVO createShare(Long fileId, CreateShareRequest request, Long userId) {
        log.info("创建文件分享: fileId={}, userId={}, request={}", fileId, userId, request);

        // 1. 检查文件是否存在
        FileEntity file = fileMapper.selectById(fileId);
        if (file == null || file.getIsDeleted()) {
            throw new BusinessException("文件不存在");
        }

        // 2. 权限检查：必须是文件上传者或有share权限
        if (!file.getUploadedBy().equals(userId) &&
            !permissionService.checkPermission(userId, "file:" + fileId, "share")) {
            throw new ForbiddenException("无权限分享此文件");
        }

        // 3. 检查是否已存在未过期的分享（简化版：允许重复分享）
        // 实际生产环境可能需要限制单个文件的分享数量

        // 4. 生成分享码（UUID去掉连字符，取前9位）
        String shareCode = UUID.randomUUID().toString().replace("-", "").substring(0, 9);

        // 5. 创建分享实体
        FileShareEntity entity = new FileShareEntity();
        entity.setFileId(fileId);
        entity.setShareCode(shareCode);
        entity.setShareType(request.getShareType() != null ? request.getShareType() : "link");

        // 密码处理（简化版：明文存储，生产环境应加密）
        if (request.getPassword() != null && !request.getPassword().isEmpty()) {
            if (request.getPassword().length() < 4 || request.getPassword().length() > 8) {
                throw new BusinessException("密码长度必须为4-8位");
            }
            entity.setSharePassword(request.getPassword());
        }

        // 过期时间处理
        entity.setExpireTime(request.getExpireTime());
        if (request.getExpireTime() != null) {
            entity.setExpireType("time");
        } else {
            entity.setExpireType("permanent");
        }

        // 下载限制
        entity.setMaxDownload(request.getMaxDownload());
        entity.setDownloadCount(0);
        entity.setViewCount(0);

        entity.setCreatedBy(userId);
        entity.setCreatedAt(LocalDateTime.now());
        entity.setUpdatedAt(LocalDateTime.now());

        // 6. 保存到数据库
        fileShareMapper.insert(entity);

        log.info("文件分享创建成功: shareId={}, shareCode={}", entity.getId(), shareCode);

        // 7. 返回VO
        return FileShareVO.builder()
                .id(entity.getId())
                .fileId(fileId)
                .fileName(file.getFileName())
                .shareCode(shareCode)
                .shareUrl(baseUrl + "/share/" + shareCode)
                .hasPassword(entity.getSharePassword() != null)
                .expireTime(entity.getExpireTime())
                .isExpired(false)
                .allowDownload(request.getAllowDownload() != null ? request.getAllowDownload() : true)
                .viewCount(0)
                .downloadCount(0)
                .maxDownload(entity.getMaxDownload())
                .createdAt(entity.getCreatedAt())
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccessShareResponse accessShare(String shareCode, String password) {
        log.info("访问分享链接: shareCode={}", shareCode);

        // 1. 查询分享记录
        LambdaQueryWrapper<FileShareEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileShareEntity::getShareCode, shareCode);

        FileShareEntity share = fileShareMapper.selectOne(wrapper);
        if (share == null) {
            throw new BusinessException("分享链接不存在");
        }

        // 2. 检查是否过期
        if (share.getExpireTime() != null && LocalDateTime.now().isAfter(share.getExpireTime())) {
            throw new BusinessException("分享链接已过期");
        }

        // 3. 验证密码
        if (share.getSharePassword() != null && !share.getSharePassword().isEmpty()) {
            if (password == null || !share.getSharePassword().equals(password)) {
                throw new ForbiddenException("访问密码错误");
            }
        }

        // 4. 检查下载次数限制
        if (share.getMaxDownload() != null && share.getDownloadCount() >= share.getMaxDownload()) {
            throw new BusinessException("下载次数已达上限");
        }

        // 5. 增加访问次数
        share.setViewCount(share.getViewCount() + 1);
        fileShareMapper.updateById(share);

        // 6. 查询文件信息
        FileEntity file = fileMapper.selectById(share.getFileId());
        if (file == null || file.getIsDeleted()) {
            throw new BusinessException("文件已被删除");
        }

        // 7. 查询分享者信息
        UserEntity sharer = userMapper.selectById(share.getCreatedBy());

        // 8. 构造响应
        return AccessShareResponse.builder()
                .file(AccessShareResponse.FileInfo.builder()
                        .id(file.getId())
                        .name(file.getFileName())
                        .size(file.getFileSize())
                        .extension(file.getExtension())
                        .previewUrl("/api/v1/share/" + shareCode + "/preview")
                        .downloadUrl("/api/v1/share/" + shareCode + "/download")
                        .build())
                .sharer(AccessShareResponse.SharerInfo.builder()
                        .name(sharer != null ? sharer.getUsername() : "未知用户")
                        .avatar(null)  // TODO: 用户头像字段
                        .build())
                .expireTime(share.getExpireTime())
                .allowDownload(true)  // TODO: 根据实际字段判断
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelShare(Long fileId, Long shareId, Long userId) {
        log.info("取消文件分享: fileId={}, shareId={}, userId={}", fileId, shareId, userId);

        // 1. 检查文件是否存在
        FileEntity file = fileMapper.selectById(fileId);
        if (file == null || file.getIsDeleted()) {
            throw new BusinessException("文件不存在");
        }

        // 2. 查询分享记录
        FileShareEntity share = fileShareMapper.selectById(shareId);
        if (share == null || !share.getFileId().equals(fileId)) {
            throw new BusinessException("分享记录不存在");
        }

        // 3. 权限检查：只有创建者可以取消分享
        if (!share.getCreatedBy().equals(userId)) {
            throw new ForbiddenException("无权限取消此分享");
        }

        // 4. 删除分享记录
        fileShareMapper.deleteById(shareId);

        log.info("文件分享已取消: shareId={}", shareId);
    }

    @Override
    public PagedResult<FileShareVO> listMyShares(Long userId, Integer page, Integer pageSize) {
        log.info("查询我的分享: userId={}, page={}, pageSize={}", userId, page, pageSize);

        // 参数默认值
        if (page == null || page < 1) page = 1;
        if (pageSize == null || pageSize < 1) pageSize = 20;

        // 查询我的分享
        LambdaQueryWrapper<FileShareEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileShareEntity::getCreatedBy, userId)
               .orderByDesc(FileShareEntity::getCreatedAt);

        List<FileShareEntity> allShares = fileShareMapper.selectList(wrapper);

        // 手动分页
        int total = allShares.size();
        int start = (page - 1) * pageSize;
        int end = Math.min(start + pageSize, total);
        List<FileShareEntity> pagedShares = (start < total) ?
                allShares.subList(start, end) : List.of();

        // 转换为VO
        List<FileShareVO> items = pagedShares.stream()
                .map(this::entityToVO)
                .collect(Collectors.toList());

        // 构造分页响应
        return PagedResult.<FileShareVO>builder()
                .items(items)
                .pagination(PagedResult.Pagination.builder()
                        .page(page)
                        .pageSize(pageSize)
                        .total((long) total)
                        .totalPages((int) Math.ceil((double) total / pageSize))
                        .build())
                .build();
    }

    /**
     * 实体转VO
     */
    private FileShareVO entityToVO(FileShareEntity entity) {
        // 查询文件名
        FileEntity file = fileMapper.selectById(entity.getFileId());
        String fileName = file != null ? file.getFileName() : "未知文件";

        // 检查是否过期
        boolean isExpired = entity.getExpireTime() != null &&
                LocalDateTime.now().isAfter(entity.getExpireTime());

        return FileShareVO.builder()
                .id(entity.getId())
                .fileId(entity.getFileId())
                .fileName(fileName)
                .shareCode(entity.getShareCode())
                .shareUrl(baseUrl + "/share/" + entity.getShareCode())
                .hasPassword(entity.getSharePassword() != null && !entity.getSharePassword().isEmpty())
                .expireTime(entity.getExpireTime())
                .isExpired(isExpired)
                .allowDownload(true)  // TODO: 根据实际字段
                .viewCount(entity.getViewCount())
                .downloadCount(entity.getDownloadCount())
                .maxDownload(entity.getMaxDownload())
                .createdAt(entity.getCreatedAt())
                .build();
    }
}
